package bma.common.langutil.jmshell.cmdopt;

import java.util.Locale;

import bma.common.langutil.core.StringUtil;

/**
 * Representation of a command-line option
 * 
 * @param T
 *            Type of data configured by this option
 */
public abstract class Option<T> {

	protected Option(Class<T> vtype, String shortForm, String longForm,
			boolean wantsValue, String tips) {
		if (longForm == null) {
			throw new IllegalArgumentException("Null longForm not allowed");
		}
		this.valueClass = vtype;
		this.shortForm = shortForm;
		this.longForm = longForm;
		this.wantsValue = wantsValue;
		this.tips = tips;
	}

	protected Option(Class<T> vtype, char shortForm, String longForm,
			boolean wantsValue, String tips) {
		this(vtype,
				shortForm > 0 ? new String(new char[] { shortForm }) : null,
				longForm, wantsValue, tips);
	}

	public String shortForm() {
		return this.shortForm;
	}

	public String longForm() {
		return this.longForm;
	}

	/**
	 * Tells whether or not this option wants a value
	 */
	public boolean wantsValue() {
		return this.wantsValue;
	}

	public final T getValue(String arg, Locale locale)
			throws IllegalOptionValueException {
		if (this.wantsValue) {
			if (arg == null) {
				throw new IllegalOptionValueException(this, "");
			}
			return this.parseValue(arg, locale);
		} else {
			return this.getDefaultValue();
		}
	}

	/**
	 * Override to extract and convert an option value passed on the
	 * command-line
	 */
	protected T parseValue(String arg, Locale locale)
			throws IllegalOptionValueException {

		return null;
	}

	/**
	 * Override to define default value returned by getValue if option does not
	 * want a value
	 */
	protected T getDefaultValue() {
		return null;
	}

	private String shortForm;
	private String longForm;
	private boolean wantsValue;
	private Class<T> valueClass;
	private String helpString;
	private String tips;

	public String getTips() {
		return tips;
	}

	public void setTips(String tips) {
		this.tips = tips;
	}

	public String getHelpString() {
		if (helpString == null)
			return makeHelp();
		return helpString;
	}

	public void setHelpString(String helpString) {
		this.helpString = helpString;
	}

	public Class<T> getValueClass() {
		return valueClass;
	}

	public void setValueClass(Class<T> valueClass) {
		this.valueClass = valueClass;
	}

	public String makeHelp() {
		StringBuilder sb = new StringBuilder();
		if (shortForm() != null) {
			sb.append(" -").append(shortForm());
		}
		if (longForm() != null) {
			if (sb.length() != 0)
				sb.append("/");
			sb.append("--").append(longForm());
		}
		if (tips != null) {
			sb.append(": ").append(tips);
		}
		return sb.toString();
	}

	public boolean is(String name) {
		return StringUtil.equals(name, longForm());
	}
}